package com.yanqu.road.server.manager.match;

import com.yanqu.road.entity.config.match.MatchInfo;
import com.yanqu.road.entity.match.MatchData;
import com.yanqu.road.entity.match.UserMatchData;
import com.yanqu.road.logic.bussiness.match.MatchBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.variety.VarietyProto;
import com.yanqu.road.server.pb.CrossVarietyPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.date.DateHelper;

import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ：zfr
 * @date ：2021/2/4 10:21
 * 赛事
 */
public class Match {
    /**
     * 杂艺数据
     */
    private MatchData matchData;
    /**
     * 玩家数据map
     * serverId-userId-userMatchData
     */
    private Map<Long, Map<Long, UserMatchData>> userDataMap = new ConcurrentHashMap<>();
    /**
     * 排序
     */
    private List<UserMatchData> sortList = new ArrayList<>();

    /**
     * 派遣队伍
     *
     * @param serverId 服务器id
     * @param userId   玩家id
     * @param msg
     * @param respMsg
     */
    public void dispatchTeam(long serverId, long userId, VarietyProto.DispatchTeamCrossReqMsg msg, VarietyProto.DispatchTeamCrossRespMsg.Builder respMsg) {
        synchronized (userDataMap) {
            if (matchData.isOverForGroupChange()) {
                respMsg.setRet(GameErrorCode.E_VARIETY_OVER_TIME);
                return;
            }
            //检查房间是否已满
            if (checkFull()) {
                respMsg.setRet(GameErrorCode.E_VARIETY_IS_FULL);
                return;
            }
            if (!userDataMap.containsKey(serverId)) {
                userDataMap.put(serverId, new ConcurrentHashMap<>());
            }
            if (userDataMap.get(serverId).containsKey(userId)) {
                respMsg.setRet(GameErrorCode.E_VARIETY_ALREADY_JOIN);
                return;
            }
            if (matchData.getType() != 0 && matchData.getType() != msg.getOccapution()) {
                respMsg.setRet(GameErrorCode.E_VARIETY_DISPATCH_PATRONS_OCCUPATION_ERROR);
                return;
            }
            if (matchData.getLevel() != msg.getLevel()) {
                respMsg.setRet(GameErrorCode.E_REQUEST_ARGUMENT_ERROR);
                return;
            }

            UserMatchData data = new UserMatchData();
            data.setGroupId(matchData.getGroupId());
            data.setTimeId(matchData.getTimeId());
            data.setServerId(serverId);
            data.setUserId(userId);
            data.setId(matchData.getId());
            data.setUserBaseInfo(PlayerBasePb.parseToUserBaseInfo(msg.getPlayerBaseData()));

            //解析门客数据
            Map<Integer, BigInteger> patronsMap = new ConcurrentHashMap<>();
            for (VarietyProto.PatronsTemp patronsTemp : msg.getPatronsList()) {
                patronsMap.put(patronsTemp.getPatronsId(), BigInteger.valueOf(patronsTemp.getEarnSpeed()));
            }
            data.setPatronsMap(patronsMap);

            //计算派遣的门客总赚速
            BigInteger totalEarnSpeed = BigInteger.ZERO;
            for (BigInteger value : data.getPatronsMap().values()) {
                totalEarnSpeed = totalEarnSpeed.add(value);
            }
            data.setTotalEarnSpeed(totalEarnSpeed);

            //随机座位
            int seat = nextSeat();
            data.setSeat(seat);
            data.setDispatchTime(System.currentTimeMillis());
            data.setInsertOption();
            userDataMap.get(serverId).put(userId, data);

            //排序
            sortMatch();
            respMsg.setRet(0);
        }
    }

    /**
     * 检查房间是否已满
     *
     * @return
     */
    private boolean checkFull() {
        int userNum = getVarietyUserNum();
        MatchInfo matchInfo = CrossMatchConfigMgr.getMatchInfo(matchData.getLevel(), matchData.getMatchId());
        if (matchInfo != null) {
            return matchInfo.getUserNumLimit() <= userNum;
        }
        return false;
    }

    /**
     * 根据玩家派遣的门客总赚速排序
     */
    private void sortMatch() {
        sortList = new ArrayList<>();
        for (Map<Long, UserMatchData> map : userDataMap.values()) {
            sortList.addAll(map.values());
        }
        sortList.sort(Comparator.comparing(UserMatchData::getTotalEarnSpeed).reversed().thenComparing(UserMatchData::getDispatchTime));
    }

    /**
     * 检查派遣时间合法性
     */
    public boolean checkIsInRewardTime() {
        if (matchData.getTimeId() >= Integer.parseInt(DateHelper.getPyyyyMMddDateString(System.currentTimeMillis() / 1000))) {
            long zeroTime = DateHelper.getTodayZeroTimeStamp();
            long nowTime = System.currentTimeMillis();
            //5分钟结算时间
            return nowTime > (zeroTime + (GameConfig.VARIETY_END_TIME + 5) * 60 * 1000);
        }
        return true;
    }

    /**
     * 领奖
     *
     * @param serverId 服务器id
     * @param userId   玩家id
     * @param respMsg
     */
    public void getReward(long serverId, long userId, VarietyProto.GetRewardCrossRespMsg.Builder respMsg) {
        synchronized (userDataMap) {
            if (!checkIsInRewardTime() && !matchData.isOverForGroupChange()) {
                return;
            }
            if (!userDataMap.containsKey(serverId)) {
                return;
            }
            if (!userDataMap.get(serverId).containsKey(userId)) {
                return;
            }
            UserMatchData userMatchData = userDataMap.get(serverId).get(userId);
            int index = 0;
            for (UserMatchData data : sortList) {
                index++;
                if (data.getServerId() == serverId && data.getUserId() == userId) {
                    break;
                }
            }
            //ok 发奖
            respMsg.addRank(CrossVarietyPb.parseVarietyRank(matchData.getTimeId(), matchData.getLevel(), matchData.getType(),
                    matchData.getMatchId(), matchData.getId(), userMatchData.getPatronsMap().keySet(), index));
        }
    }

    /**
     * 是否在该杂艺赛事中
     *
     * @param serverId 区服id
     * @param userId   玩家id
     * @return
     */
    public boolean isJoin(long serverId, long userId) {
        if (userDataMap.containsKey(serverId)) {
            return userDataMap.get(serverId).containsKey(userId);
        }
        return false;
    }

    /**
     * 计算杂艺赛事内玩家数量
     *
     * @return
     */
    public int getVarietyUserNum() {
        int num = 0;
        for (Map<Long, UserMatchData> dataMap : userDataMap.values()) {
            num += dataMap.size();
        }
        return num;
    }

    /**
     * 获取玩家数据
     *
     * @param serverId
     * @param userId
     * @return
     */
    public UserMatchData getUserMatchData(long serverId, long userId) {
        if (userDataMap.containsKey(serverId)) {
            return userDataMap.get(serverId).get(userId);
        }
        return null;
    }

    /**
     * 座位
     * @return
     */
    public int nextSeat() {
        int seat = 0;
        for (Map<Long, UserMatchData> map : userDataMap.values()) {
            seat += map.size();
        }
        return seat;
    }

    public MatchData getMatchData() {
        return matchData;
    }

    public void setMatchData(MatchData matchData) {
        this.matchData = matchData;
    }

    /**
     * 读库 初始化玩家数据
     * @param userMatchDataList 玩家数据集合
     */
    public void initUserDataMap(List<UserMatchData> userMatchDataList) {
        synchronized (userDataMap) {
            for (UserMatchData data : userMatchDataList) {
                if (!userDataMap.containsKey(data.getServerId())) {
                    userDataMap.put(data.getServerId(), new ConcurrentHashMap<>());
                }
                userDataMap.get(data.getServerId()).put(data.getUserId(), data);
            }
            sortMatch();
        }
    }

    public void save() {
        if (matchData.isInsertOption()) {
            MatchBussiness.addData(matchData);
        } else if (matchData.isUpdateOption()) {
            MatchBussiness.updateData(matchData);
        }

        for (Map<Long, UserMatchData> dataMap : userDataMap.values()) {
            for (UserMatchData data : dataMap.values()) {
                if (data.isInsertOption()) {
                    MatchBussiness.addData(data);
                } else if (data.isUpdateOption()) {
                    MatchBussiness.updateData(data);
                }
            }
        }
    }

    /**
     * 同步杂艺详细数据
     * @param respMsg
     */
    public void syncVarietyDetailData(VarietyProto.SyncVarietyDetailRespMsg.Builder respMsg) {
        synchronized (userDataMap) {
            respMsg.setCurrentNum(getVarietyUserNum());
            MatchInfo matchInfo = CrossMatchConfigMgr.getMatchInfo(matchData.getLevel(), matchData.getMatchId());
            respMsg.setMaxNum(matchInfo != null ? matchInfo.getUserNumLimit() : 0);
            for (Map<Long, UserMatchData> dataMap : userDataMap.values()) {
                for (UserMatchData data : dataMap.values()) {
                    VarietyProto.VarietyUserBaseData.Builder builder = VarietyProto.VarietyUserBaseData.newBuilder();
                    builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(data.getUserBaseInfo()));
                    builder.setSeat(data.getSeat());
                    builder.setUserId(data.getUserId());
                    respMsg.addPlayerBaseData(builder);
                }
            }
        }
    }

    /**
     * 获取杂艺排行列表
     * @param serverId
     * @param playerId
     * @param respMsg
     */
    public void getVarietyRank(long serverId, long playerId, VarietyProto.GetVarietyRankRespMsg.Builder respMsg) {
        int myRank = 0;
        for (UserMatchData userMatchData : sortList) {
            myRank++;
            VarietyProto.VarietyRankTemp.Builder rank = VarietyProto.VarietyRankTemp.newBuilder();
            rank.setUserId(userMatchData.getUserId());
            rank.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userMatchData.getUserBaseInfo()));
            rank.setTotalEarnSpeed(userMatchData.getTotalEarnSpeed().longValue());
            rank.addAllPatronsId(userMatchData.getPatronsMap().keySet());
            respMsg.addRank(rank);
            if (userMatchData.getServerId() == serverId && userMatchData.getUserId() == playerId) {
                respMsg.setMyRank(myRank);
                respMsg.setMyTotalEarnSpeed(userMatchData.getTotalEarnSpeed().longValue());
            }
        }
    }

    /**
     * 获取玩家排行
     * @param userMatchData
     * @return
     */
    public int getUserRank(UserMatchData userMatchData) {
        synchronized (sortList) {
            int rank = 0;
            for (UserMatchData sort : sortList) {
                rank++;
                if (sort.getServerId() == userMatchData.getServerId() && sort.getUserId() == userMatchData.getUserId()) {
                    return rank;
                }
            }
            return rank;
        }
    }

    /**
     * 同步门客赚钱
     * @param serverId
     * @param playerId
     * @param syncPatronsTempList
     */
    public void syncPatronsAbility(long serverId, long playerId, List<VarietyProto.SyncPatronsTemp> syncPatronsTempList) {
        Map<Long, UserMatchData> userMatchDataMap = userDataMap.get(serverId);
        if (userMatchDataMap != null) {
            UserMatchData data = userMatchDataMap.get(playerId);
            for (Map.Entry<Integer, BigInteger> patronsEntry : data.getPatronsMap().entrySet()) {
                for (VarietyProto.SyncPatronsTemp temp : syncPatronsTempList) {
                    if (temp.getPatronsId() == patronsEntry.getKey()) {
                        patronsEntry.setValue(BigInteger.valueOf(temp.getAbility()));
                    }
                }
            }
            //计算派遣的门客总赚速
            BigInteger totalEarnSpeed = BigInteger.ZERO;
            for (BigInteger value : data.getPatronsMap().values()) {
                totalEarnSpeed = totalEarnSpeed.add(value);
            }
            data.setTotalEarnSpeed(totalEarnSpeed);
            data.setUpdateOption();
            //排序
            sortMatch();
        }
    }
}
